package com.mcxx.modules.extremepoverty.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.mcxx.common.exception.BizException;
import com.mcxx.constant.MQConstant;
import com.mcxx.modules.extremepoverty.service.ExCustomFundPayService;
import com.mcxx.modules.base.utils.excel.ImportExcel;
import com.mcxx.modules.miniSalvation.fundpay.dao.write.FundPayFamilyWriteDao;
import com.mcxx.modules.miniSalvation.fundpay.dao.write.FundPayMemberWriteDao;
import com.mcxx.modules.miniSalvation.fundpay.dto.CustomFundPayDTO;
import com.mcxx.modules.miniSalvation.fundpay.dto.CustomFundPayMemberDTO;
import com.mcxx.modules.miniSalvation.fundpay.entity.CustomFundPayMemberEntity;
import com.mcxx.modules.miniSalvation.fundpay.entity.FundPayEntity;
import com.mcxx.modules.miniSalvation.fundpay.entity.FundPayFamilyEntity;
import com.mcxx.modules.miniSalvation.fundpay.entity.FundPayMemberEntity;
import com.mcxx.modules.miniSalvation.fundpay.param.CustomFundPayMemberParam;
import com.mcxx.modules.miniSalvation.fundpay.service.read.CustomFundPayMemberReadService;
import com.mcxx.modules.miniSalvation.fundpay.service.read.CustomFundPayReadService;
import com.mcxx.modules.miniSalvation.fundpay.service.read.FundPayFamilyReadService;
import com.mcxx.modules.miniSalvation.fundpay.service.read.FundPayMemberReadService;
import com.mcxx.modules.miniSalvation.fundpay.service.write.CustomFundPayMemberWriteService;
import com.mcxx.modules.miniSalvation.fundpay.service.write.CustomFundPayWriteService;
import com.mcxx.modules.miniSalvation.fundpay.service.write.FundPayFamilyWriteService;
import com.mcxx.modules.miniSalvation.salary.service.write.FamilySalaryWriteService;
import com.mcxx.modules.system.dto.MQMessageDTO;
import com.mcxx.util.Constant;
import com.yinhai.ta404.core.security.vo.UserAccountVo;
import com.yinhai.ta404.core.service.BaseService;
import com.yinhai.ta404.core.transaction.annotation.TaTransactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.util.*;
import java.util.stream.Collectors;


@Slf4j
@Service
@TaTransactional
public class ExCustomFundPayServiceImpl extends BaseService implements ExCustomFundPayService {

    @Autowired
    private CustomFundPayReadService customFundPayReadService;
    @Autowired
    private CustomFundPayWriteService customFundPayWriteService;
    @Autowired
    private CustomFundPayMemberReadService customFundPayMemberReadService;
    @Autowired
    private CustomFundPayMemberWriteService customFundPayMemberWriteService;
    @Autowired
    private FamilySalaryWriteService familySalaryWriteService;
    @Autowired
    private FundPayFamilyReadService fundPayFamilyReadService;
    @Autowired
    private FundPayMemberReadService fundPayMemberReadService;
    @Autowired
    private FundPayFamilyWriteDao fundPayFamilyWriteDao;
    @Autowired
    private FundPayMemberWriteDao fundPayMemberWriteDao;
    @Autowired
    private FundPayFamilyWriteService fundPayFamilyWriteService;


    @Override
    public void addCustomFundPay(CustomFundPayDTO customFundPayDTO) {

       customFundPayReadService.cntPayFundCount(customFundPayDTO);


        customFundPayWriteService.insert(customFundPayDTO);
    }


    @Override
    public Map<String, List<String>> delCustomFundPay(List<String> customFundPayIdList) {

        List<String> stateList = new ArrayList<String>(){{add(Constant.FundPayState.CREATE); add(Constant.FundPayState.REVOKE);}};
        Map<String, List<String>> rstMap = customFundPayReadService.getIdByIdAndStates(customFundPayIdList, stateList);
        if(rstMap.containsKey("success") == false){

            return rstMap;
        }


        int rst = customFundPayWriteService.delCustomFundPay(rstMap.get("success"));


        if(rst <= 0){

            rstMap.put("fail", customFundPayIdList);
            rstMap.remove("success");
        }

        return rstMap;
    }


    @Override
    public Map<String, List<String>> confirmCustomFundPay(List<String> customFundPayIdList, UserAccountVo userAccountVo) {

        List<String> stateList = new ArrayList<String>(){{add( Constant.FundPayState.CREATE); add( Constant.FundPayState.REVOKE);}};
        Map<String, List<String>> rstMap = customFundPayReadService.getIdByIdAndStates(customFundPayIdList, stateList);
        if(rstMap.containsKey("success") == false){

            return rstMap;
        }



        Map<String, List<String>> cntMemberMap = customFundPayReadService.getIdByIdAndMemberNum(rstMap.get("success"));

        if(cntMemberMap.containsKey("success") == false){

            rstMap.put("fail", customFundPayIdList);
            rstMap.remove("success");
            return rstMap;
        }
        if(cntMemberMap.containsKey("fail") == true){
            List<String> a = cntMemberMap.get("fail");
            rstMap.get("fail").addAll(a);
            rstMap.put("success", cntMemberMap.get("success"));
        }



        int rst = customFundPayWriteService.updateStateByIds(cntMemberMap.get("success"), Constant.FundPayState.CONFIRM);


        if(rst <= 0){

            rstMap.put("fail", customFundPayIdList);
            rstMap.remove("success");
        }

        return rstMap;
    }


    @Override
    public Map<String, List<String>> cancelCustomFundPay(List<String> fundPayIdList) {

        Map<String, List<String>> rstMap = customFundPayReadService.getIdByIdAndState(fundPayIdList, Constant.FundPayState.CONFIRM);
        if(rstMap.containsKey("success") == false){

            return rstMap;
        }


        familySalaryWriteService.deleteByCustomFundPayId(fundPayIdList);


        int rst = customFundPayWriteService.updateStateByIds(rstMap.get("success"), Constant.FundPayState.REVOKE);
        if(rst <= 0){

            rstMap.put("fail", fundPayIdList);
            rstMap.remove("success");
        }

        return rstMap;
    }


    @Override
    public void addCustomFundPayObjects(String customFundPayId, List<String> memberIdList, UserAccountVo userAccountVo) {

        CustomFundPayDTO customFundPayDTO = customFundPayReadService.getById(customFundPayId);


        List<CustomFundPayMemberEntity> customFundPayMemberList = customFundPayMemberReadService.getCustomMemberListByMemberId(customFundPayDTO, memberIdList, userAccountVo);


       customFundPayMemberWriteService.inserts(customFundPayMemberList, customFundPayId);


        customFundPayWriteService.updateAddMemberNum(customFundPayId, customFundPayMemberList.size());
    }



    @Override
    public String importCustomFundPayObjects(String customFundPayId, MultipartFile file, UserAccountVo curUserAccount) {
        log.info("特困自定义导入》》》》》》》》》》》》》》》");

        Map<String, FundPayMemberEntity> excelMemberMap = ImportExcel.importExcelCustomFundPay(file);


        FundPayEntity customFundPayDTO = fundPayFamilyReadService.getCustomRollById(customFundPayId);
        if (null == customFundPayDTO) {
            throw new BizException("-1", "名册异常，无法导入数据");
        }



        List<String> idCardList = new ArrayList<>(excelMemberMap.keySet());

        List<FundPayMemberEntity> canAddMemberList = fundPayFamilyReadService.getCustomMemberListByIdcard(customFundPayDTO, idCardList, curUserAccount);
        if (canAddMemberList.size() == 0) {
            throw new BizException("-1", "没有可以导入到选中的补发名册的成员，或者选择的名册与导入对象的类型不匹配，请核对");
        }


        List<FundPayMemberEntity> rollMembers = fundPayMemberReadService.getByFundPayId(customFundPayId);


        for (FundPayMemberEntity obj : canAddMemberList) {
            FundPayMemberEntity memberEntity = excelMemberMap.get(obj.getIdcard());
            if (memberEntity == null) {
                throw new BizException("-1", "导入失败，身份证号【" + obj.getIdcard() + "】数据有误，请检查");
            }
            if (memberEntity.getPersonNumber() > 1) {
                throw new BizException("-1", "导入失败，暂不支持家庭信息导入，请按成员信息导入");
            }
            Double fundNumber = memberEntity.getFundNumber();
            obj.setFundNumber(fundNumber);
        }



        List<FundPayMemberEntity> sameList = canAddMemberList.stream()
                .filter(item -> rollMembers.stream().map(FundPayMemberEntity::getMemberId)
                        .collect(Collectors.toList()).contains(item.getMemberId()))
                .collect(Collectors.toList());

        Map<String, List<FundPayMemberEntity>> listMap = sameList.stream().collect(Collectors.groupingBy(FundPayMemberEntity::getMemberId));
        Set<String> memberIds = listMap.keySet();

        if (memberIds .size() > 0 ) {
            fundPayMemberWriteDao.deleteByFundPayIdAndIdCard(customFundPayId,memberIds);
        }

        fundPayFamilyWriteDao.deleteByFundPayIds(Arrays.asList(customFundPayId.split(",")));


        List<FundPayMemberEntity> rollMemberLastDb = fundPayMemberReadService.getByFundPayId(customFundPayId);

        List<FundPayMemberEntity> memberList = fundPayFamilyWriteService.partMemberInfo(canAddMemberList, excelMemberMap, customFundPayId, customFundPayDTO);

        canAddMemberList.addAll(rollMemberLastDb);

        Integer familyNum = 0;

        if (canAddMemberList.size() > 0) {

            Map<String, List<FundPayMemberEntity>> diffMemberMap = canAddMemberList.stream().collect(Collectors.groupingBy(FundPayMemberEntity::getFamilyId));
            Set<String> familyIds = diffMemberMap.keySet();
            familyNum = familyIds.size();
            List<FundPayFamilyEntity> results = new ArrayList<>();
            for (String familyId : familyIds) {
                List<FundPayMemberEntity> sameFamilyMember = diffMemberMap.get(familyId);
                Double sumFundNumber = sameFamilyMember.stream().mapToDouble(FundPayMemberEntity::getFundNumber).sum();
                FundPayFamilyEntity familyDTO = new FundPayFamilyEntity ();
                familyDTO.setId(Constant.getUUID());
                familyDTO.setFundPayId(customFundPayId);
                familyDTO.setOrderId(sameFamilyMember.get(0).getOrderId());
                familyDTO.setFamilyId(sameFamilyMember.get(0).getFamilyId());
                familyDTO.setMemberId(sameFamilyMember.get(0).getMasterMemberId());
                familyDTO.setAreaCode(sameFamilyMember.get(0).getAreaCode());
                familyDTO.setPersonNumber(sameFamilyMember.size());
                familyDTO.setPayDate(customFundPayDTO.getPayDate());
                familyDTO.setCreateTime(new Date());
                familyDTO.setFundNumber(sumFundNumber);
                results.add(familyDTO);
                for (FundPayMemberEntity member : memberList) {
                    if (member.getFamilyId().equals(familyId)) {
                        member.setFundPayFamilyId(familyDTO.getId());
                    }
                }
            }

            List<List<FundPayFamilyEntity>> subFamilyList =  Lists.partition(results,1024);
            for (List<FundPayFamilyEntity> sub : subFamilyList) {
                int num = fundPayFamilyWriteDao.inserts(sub);
                if (num <= 0) {
                    throw new BizException("-1", "名册家庭信息添加失败,数据库操作异常");
                }
            }

            canAddMemberList.removeAll(rollMemberLastDb);
            List<List<FundPayMemberEntity>> subMemberList =  Lists.partition(canAddMemberList,1024);
            for (List<FundPayMemberEntity> sub : subMemberList) {
                int rst = fundPayFamilyWriteService.insertRollMembers(sub);
                if (rst <= 0) {
                    throw new BizException("-1", "成员添加失败,数据库操作异常");
                }
            }

        }

        fundPayFamilyWriteService.updateAddMemberNum(customFundPayId, canAddMemberList.size() + rollMemberLastDb.size(), familyNum);

        return packageRstMsgMin(excelMemberMap, canAddMemberList);
    }

    private String packageRstMsgMin(Map<String, FundPayMemberEntity> allExcelMemberMap, List<FundPayMemberEntity> addSuccessMemberList) {
        if (allExcelMemberMap.size() == addSuccessMemberList.size()) {

            return "导入成功";
        }
        List<String> addSuccessIdcardList = addSuccessMemberList.stream().map(FundPayMemberEntity::getIdcard).collect(Collectors.toList());
        StringBuffer rstNames = new StringBuffer("导入成功，其中【");
        for (String idcard : allExcelMemberMap.keySet()) {

            if (addSuccessIdcardList.contains(idcard) == false) {
                rstNames.append(allExcelMemberMap.get(idcard).getName()).append("、");
            }
        }
        rstNames.deleteCharAt(rstNames.length() - 1).append("】用户信息未找到");
        return rstNames.toString();
    }

    @Override
    public int delCustomFundPayObjects(String customFundPayId, List<String> memberIdList) {

        customFundPayMemberWriteService.deleteByCustomFundPayIdAndMemberId(customFundPayId, memberIdList);


        customFundPayWriteService.updateSubMemberNum(customFundPayId, memberIdList.size());

        return 1;
    }

    @Override
    public void updateMemberFundNumber(CustomFundPayMemberDTO customFundPayMemberDTO) {

        customFundPayMemberWriteService.updateById(customFundPayMemberDTO);


        customFundPayWriteService.updatePayTotal(customFundPayMemberDTO.getCustomFundPayId());
    }


    private String packageRstMsg(Map<String, CustomFundPayMemberDTO> allExcelMemberMap, List<CustomFundPayMemberEntity> addSuccessMemberList){
        if(allExcelMemberMap.size() == addSuccessMemberList.size()){

            return "导入成功";
        }
        List<String> addSuccessIdcardList = addSuccessMemberList.stream().map(CustomFundPayMemberEntity::getIdcard).collect(Collectors.toList());
        StringBuffer rstNames = new StringBuffer("导入成功，其中【");
        for(String idcard : allExcelMemberMap.keySet()){

            if(addSuccessIdcardList.contains(idcard) == false){
                rstNames.append(allExcelMemberMap.get(idcard).getName()).append("、");
            }
        }
        rstNames.deleteCharAt(rstNames.length() - 1).append("】用户信息未找到");
        return rstNames.toString();
    }



}
